// ============================================================================
//
// Copyright (C) 2006-2007 Dengues
//
// Google Group: http://groups.google.com/group/dengues
//
// QQ Group: 24885404
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// ============================================================================
package org.dengues.reports.editor.design;

import org.dengues.reports.editor.design.layout.ReportDesignLayout;
import org.dengues.reports.editor.design.tools.RootDragTracker;
import org.eclipse.draw2d.ColorConstants;
import org.eclipse.draw2d.ConnectionLayer;
import org.eclipse.draw2d.FreeformLayer;
import org.eclipse.draw2d.FreeformLayeredPane;
import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.LayeredPane;
import org.eclipse.draw2d.PositionConstants;
import org.eclipse.draw2d.Viewport;
import org.eclipse.draw2d.geometry.Insets;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.AutoexposeHelper;
import org.eclipse.gef.DragTracker;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.Request;
import org.eclipse.gef.editparts.ScalableFreeformRootEditPart;
import org.eclipse.gef.editparts.ViewportAutoexposeHelper;

/**
 * Qiang.Zhang.Adolf@gmail.com class global comment. Detailled comment <br/>
 * 
 * $Id: Dengues.epf Qiang.Zhang.Adolf@gmail.com 2008-1-25 qiang.zhang $
 * 
 */
public class ReportRootEditPart extends ScalableFreeformRootEditPart {

    public static final String LAYOUT_SIZE = "Layout Size"; //$NON-NLS-1$

    public static final String REPORT_SIZE = "Report Size"; //$NON-NLS-1$

    public static final String RULER_SIZE = "Ruler Size"; //$NON-NLS-1$

    /**
     * Qiang.Zhang.Adolf@gmail.com ReportRootEditPart constructor comment.
     */
    public ReportRootEditPart() {
        super();
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.gef.EditPart#getDragTracker(org.eclipse.gef.Request)
     */
    public DragTracker getDragTracker(Request req) {
        return new RootDragTracker();
    }

    /**
     * Creates a layered pane and the layers that should be printed.
     * 
     * @see org.eclipse.gef.print.PrintGraphicalViewerOperation
     * @return a new LayeredPane containing the printable layers
     */
    protected LayeredPane createPrintableLayers() {
        FreeformLayeredPane layeredPane = new FreeformLayeredPane() {

            protected void paintFigure(Graphics graphics) {
                graphics.setBackgroundColor(ColorConstants.gray);
                graphics.fillRectangle(getBounds());
            }
        };

        FreeformLayer layer = new FreeformLayer() {

            /*
             * (non-Javadoc)
             * 
             * @see org.eclipse.draw2d.FreeformLayer#getFreeformExtent()
             */
            public Rectangle getFreeformExtent() {
                Rectangle rect = super.getFreeformExtent();
                Rectangle retValue = rect.getCopy();
                Object obj = getViewer().getProperty(REPORT_SIZE);
                if (obj instanceof Rectangle) {
                    Rectangle temp = (Rectangle) obj;
                    if (temp.width - rect.right() <= ReportDesignLayout.MINRIGHTSPACE) {
                        retValue.width = retValue.width + ReportDesignLayout.MINRIGHTSPACE;
                    }
                    if (temp.height - rect.bottom() <= ReportDesignLayout.MINBOTTOMSPACE) {
                        retValue.height = retValue.height + ReportDesignLayout.MINBOTTOMSPACE;
                    }

                }
                return retValue;
            }
        };
        layeredPane.add(layer, PRIMARY_LAYER);

        layeredPane.add(new ConnectionLayer(), CONNECTION_LAYER);
        return layeredPane;
    }

    /**
     * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
     */
    public Object getAdapter(Class adapter) {
        if (adapter == AutoexposeHelper.class)
            return new ReportViewportAutoexposeHelper(this);
        // if (adapter == IModelEventProcessor.class) {
        // return getContents().getAdapter(IModelEventProcessor.class);
        // }
        return super.getAdapter(adapter);
    }

    private static class ReportViewportAutoexposeHelper extends ViewportAutoexposeHelper {

        /** defines the range where autoscroll is active inside a viewer */
        private static final Insets DEFAULT_EXPOSE_THRESHOLD = new Insets(18);

        /** the last time an auto expose was performed */
        private long lastStepTime = 0;

        /** The insets for this helper. */
        private Insets threshold;

        /**
         * Constructs a new helper on the given GraphicalEditPart. The editpart must have a <code>Viewport</code>
         * somewhere between its <i>contentsPane </i> and its <i>figure </i> inclusively.
         * 
         * @param owner the GraphicalEditPart that owns the Viewport
         */
        public ReportViewportAutoexposeHelper(GraphicalEditPart owner) {
            super(owner);
            threshold = DEFAULT_EXPOSE_THRESHOLD;
        }

        /**
         * Constructs a new helper on the given GraphicalEditPart. The editpart must have a <code>Viewport</code>
         * somewhere between its <i>contentsPane </i> and its <i>figure </i> inclusively.
         * 
         * @param owner the GraphicalEditPart that owns the Viewport
         * @param threshold the Expose Threshold to use when determing whether or not a scroll should occur.
         */
        public ReportViewportAutoexposeHelper(GraphicalEditPart owner, Insets threshold) {
            super(owner);
            this.threshold = threshold;
        }

        /**
         * Returns <code>true</code> if the given point is inside the viewport, but near its edge.
         * 
         * @see org.eclipse.gef.AutoexposeHelper#detect(org.eclipse.draw2d.geometry.Point)
         */
        public boolean detect(Point where) {
            lastStepTime = 0;
            Viewport port = findViewport(owner);
            Rectangle rect = Rectangle.SINGLETON;
            port.getClientArea(rect);
            port.translateToParent(rect);
            port.translateToAbsolute(rect);
            return rect.contains(where) && !rect.crop(threshold).contains(where);
        }

        /**
         * Returns <code>true</code> if the given point is outside the viewport or near its edge. Scrolls the viewport
         * by a calculated (time based) amount in the current direction.
         * 
         * todo: investigate if we should allow auto expose when the pointer is outside the viewport
         * 
         * @see org.eclipse.gef.AutoexposeHelper#step(org.eclipse.draw2d.geometry.Point)
         */
        public boolean step(Point where) {
            Viewport port = findViewport(owner);

            Rectangle rect = Rectangle.SINGLETON;
            port.getClientArea(rect);
            port.translateToParent(rect);
            port.translateToAbsolute(rect);
            if (!rect.contains(where) || rect.crop(threshold).contains(where))
                return false;

            // set scroll offset (speed factor)
            int scrollOffset = 0;

            // calculate time based scroll offset
            if (lastStepTime == 0)
                lastStepTime = System.currentTimeMillis();

            // DeferredGraphicalViewer.OriginStepData stepData = ((DeferredGraphicalViewer)
            // owner.getViewer()).getOriginStepData();
            long difference = System.currentTimeMillis() - lastStepTime;

            if (difference > 0) {
                scrollOffset = ((int) difference / 3);
                lastStepTime = System.currentTimeMillis();
            }

            if (scrollOffset == 0)
                return true;

            rect.crop(threshold);

            int region = rect.getPosition(where);
            Point loc = port.getViewLocation();

            if ((region & PositionConstants.SOUTH) != 0)
                loc.y += scrollOffset;
            else if ((region & PositionConstants.NORTH) != 0)
                loc.y -= scrollOffset;

            if ((region & PositionConstants.EAST) != 0)
                loc.x += scrollOffset;
            else if ((region & PositionConstants.WEST) != 0)
                loc.x -= scrollOffset;

            // if (stepData.minX > loc.x)
            // loc.x = port.getHorizontalRangeModel().getValue();
            // if (stepData.maxX - stepData.extendX < loc.x)
            // loc.x = port.getHorizontalRangeModel().getValue();
            // if (stepData.minY > loc.y)
            // loc.y = port.getVerticalRangeModel().getValue();
            // if (stepData.maxY - stepData.extendY < loc.y)
            // loc.y = port.getVerticalRangeModel().getValue();
            port.setViewLocation(loc);

            return true;
        }

    }
}